import type { AuthConfig } from './types';
import type {
  ResourceNode,
  RoleResourceInDto,
} from '#/api/daprplus/auth/role-authorize';

// ==================== PKCE 认证相关函数 ====================

/**
 * 生成 PKCE 挑战码
 */
export const generatePKCE = async () => {
  const codeVerifier = generateCode();
  sessionStorage.setItem('code_verifier', codeVerifier);
  const codeChallenge = await generateCodeChallenge(codeVerifier);
  return codeChallenge;
};

/**
 * Base64URL 编码
 */
export function base64URLEncode(str: ArrayBuffer): string {
  return btoa(String.fromCharCode(...new Uint8Array(str)))
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=/g, '');
}

/**
 * 生成随机码
 */
export function generateCode(): string {
  const array = new Uint8Array(32);
  window.crypto.getRandomValues(array);
  return base64URLEncode(array.buffer);
}

/**
 * 生成代码挑战
 */
async function generateCodeChallenge(codeVerifier: string): Promise<string> {
  const encoder = new TextEncoder();
  const data = encoder.encode(codeVerifier);
  const digest = await window.crypto.subtle.digest('SHA-256', data);
  return base64URLEncode(digest);
}

/**
 * 获取认证配置
 */
export const authConfig = (): AuthConfig => {
  const config = {
    clientId: import.meta.env.VITE_OIDC_CLIENT_ID || 'VueApp.Client',
    authority: import.meta.env.VITE_OIDC_AUTHORITY || 'https://localhost:6610',
    redirectUri:
      import.meta.env.VITE_OIDC_REDIRECT_URI ||
      'http://localhost:5666/signin-oidc',
    scopes:
      import.meta.env.VITE_OIDC_SCOPES || 'openid profile email offline_access',
  };
  return config;
};

// ==================== 资源操作相关函数 ====================

/**
 * 检查操作是否被选中
 * @param resource 资源节点
 * @param code 操作类型码
 * @returns 是否选中
 */
export function isOperationSelected(
  resource: ResourceNode,
  code: string,
): boolean {
  return resource.operations.includes(code);
}

/**
 * 处理资源选择
 * @param resource 资源节点
 * @param selected 是否选中
 * @returns 更新后的资源节点
 */
export function handleResourceSelect(
  resource: ResourceNode,
  selected: boolean,
): ResourceNode {
  // 更新资源的选中状态
  resource.isSelected = selected;
  if (!selected) {
    resource.operations = [];
  }

  return resource;
}

/**
 * 处理操作选择
 * @param resource 资源节点
 * @param operation 操作类型
 * @param selected 是否选中
 * @returns 更新后的资源节点
 */
export function handleOperationSelect(
  resource: ResourceNode,
  operation: string,
  selected: boolean,
): ResourceNode {
  // 更新操作列表
  if (selected && !resource.operations.includes(operation)) {
    resource.operations.push(operation);
  } else if (!selected) {
    resource.operations = resource.operations.filter((op) => op !== operation);
  }

  return resource;
}

// ==================== 资源状态管理相关函数 ====================

/**
 * 检查资源列表是否有变更
 * @param resources 当前资源列表
 * @param originalResourcesState 原始资源状态
 * @returns 是否有变更
 */
export function checkResourceChanges(
  resources: ResourceNode[],
  originalResourcesState: Map<
    string,
    { isSelected: boolean; operations: string[] }
  >,
): boolean {
  if (!resources || resources.length === 0) return false;

  for (const resource of resources) {
    const originalState = originalResourcesState.get(resource.id);
    if (!originalState) return true; // 新增的资源

    // 检查选中状态是否变化
    if (originalState.isSelected !== resource.isSelected) return true;

    // 如果选中状态相同且都是选中的，检查操作是否变化
    if (resource.isSelected && originalState.isSelected) {
      // 检查操作数量是否变化
      if (originalState.operations.length !== resource.operations.length)
        return true;

      // 检查操作内容是否变化
      for (const op of resource.operations) {
        if (!originalState.operations.includes(op)) return true;
      }

      for (const op of originalState.operations) {
        if (!resource.operations.includes(op)) return true;
      }
    }
  }

  return false;
}

/**
 * 保存资源的原始状态
 * @param resources 资源列表
 * @returns 原始资源状态的Map
 */
export function saveResourceOriginalState(
  resources: ResourceNode[],
): Map<string, { isSelected: boolean; operations: string[] }> {
  const originalState = new Map<
    string,
    { isSelected: boolean; operations: string[] }
  >();

  resources.forEach((resource) => {
    originalState.set(resource.id, {
      isSelected: resource.isSelected,
      operations: [...resource.operations],
    });
  });

  return originalState;
}

// ==================== 服务管理相关函数 ====================

/**
 * 初始化服务变更状态
 * @param services 服务列表
 * @returns 初始化的服务变更状态映射
 */
export function initServiceChangesMap(
  services: { key: string; name: string }[],
): Record<string, boolean> {
  const changesMap: Record<string, boolean> = {};
  services.forEach((service) => {
    changesMap[service.key] = false;
  });
  return changesMap;
}

/**
 * 检查是否有任何服务发生变更
 * @param serviceChangesMap 服务变更状态映射
 * @returns 是否有任何变更
 */
export function hasAnyServiceChanges(
  serviceChangesMap: Record<string, boolean>,
): boolean {
  return Object.values(serviceChangesMap).some((value) => value);
}

// ==================== 资源数据转换相关函数 ====================

/**
 * 从资源列表中提取已选择的资源
 * @param resources 资源列表
 * @returns 已选择的资源映射
 */
export function extractSelectedResources(
  resources: ResourceNode[],
): Record<string, ResourceNode> {
  const selectedResources: Record<string, ResourceNode> = {};

  resources.forEach((resource) => {
    if (resource.isSelected) {
      selectedResources[resource.id] = resource;
    }
  });

  return selectedResources;
}

/**
 * 将选中的资源转换为授权DTO
 * @param selectedResources 选中的资源映射
 * @returns 授权DTO数组
 */
export function convertToRoleResourceDtos(
  selectedResources: Record<string, ResourceNode>,
): RoleResourceInDto[] {
  const dtos: RoleResourceInDto[] = [];

  for (const resourceId in selectedResources) {
    const resource = selectedResources[resourceId];
    if (resource) {
      dtos.push({
        resourceId: String(resource.id),
        operations: resource.operations || [],
      });
    }
  }

  return dtos;
}

/**
 * 收集所有选中的资源ID
 * @param selectedResourcesMap 所有服务的选中资源映射
 * @returns 所有选中的资源ID数组
 */
export function collectAllSelectedResourceIds(
  selectedResourcesMap: Record<string, Record<number, ResourceNode>>,
): string[] {
  return Object.values(selectedResourcesMap).flatMap((resources) =>
    Object.keys(resources),
  );
}
